package com.ybear.ybhotrepair.core;

import android.app.Application;
import android.content.Context;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.alibaba.fastjson.JSONObject;
import com.liulishuo.okdownload.DownloadContext;
import com.liulishuo.okdownload.DownloadListener;
import com.liulishuo.okdownload.DownloadTask;
import com.liulishuo.okdownload.core.breakpoint.BreakpointInfo;
import com.liulishuo.okdownload.core.cause.EndCause;
import com.liulishuo.okdownload.core.cause.ResumeFailedCause;
import com.ybear.ybhotrepair.BaseReqBuild;
import com.ybear.ybhotrepair.utils.AppUtil;
import com.ybear.ybhotrepair.utils.LogUtil;
import com.ybear.ybnetworkutil.HttpManage;
import com.ybear.ybnetworkutil.enums.RECOUNT_TRIGGER;
import com.ybear.ybnetworkutil.request.Request;

import java.io.File;
import java.util.List;
import java.util.Map;

/**
 * 网络请求管理器 - 内部调用
 */
class RequestManage {
    private static final String VER = "version";
    private static final String DEX_HASH = "dexHash";
    private static final String DEX_FILE_URL = "dexFileUrl";
    private static final String DEX_CHECK_ID = "dexCheckID";
    private static final String MSG = "msg";
    private static final String STATUS = "status";
    private static final String DATA = "data";

    //防止多次回调
    private boolean isComplete;

    public interface CallDownload {
        void onComplete();
    }

    private Context mContext;
    private HttpManage mHttpManage;
    private DownloadContext.QueueSet mDownloadQueueSet;
    private BaseReqBuild mBuild;

    private String token = null;

    public RequestManage(Application context) {
        mContext = context;

        mDownloadQueueSet = new DownloadContext.QueueSet()
                .setMinIntervalMillisCallbackProcess(0);

        mHttpManage = HttpManage.getInstance().init( context )
                .setMaxReCount( 5 )
                .setTriggers(
                        RECOUNT_TRIGGER.NETWORK_AVAILABLE,  //存在网络
                        RECOUNT_TRIGGER.NETWORK_SWITCH      //网络切换
                );
        mBuild = new BaseReqBuild();
    }

    /**
     * 下载文件
     * @param savePath  保存地址
     * @param call      下载回调
     * @param urls      文件地址
     */
    public void startDownloadService(@NonNull String savePath, @Nullable CallDownload call,
                                     @NonNull String... urls) {
        isComplete = false;

        DownloadContext.Builder b = mDownloadQueueSet
                .setParentPath( doSavePath( savePath ) )
                .commit();
        //加入下载地址
        for (String url : urls) { b.bind( url ); }
        //串行下载
        b.build().startOnSerial(new DownloadAdapter() {
            @Override
            public void taskEnd(@NonNull DownloadTask task,
                                @NonNull EndCause cause,
                                @Nullable Exception realCause) {
                super.taskEnd(task, cause, realCause);
                isComplete = true;
                //回调下载完毕
                if( call != null ) call.onComplete();
            }
        });
    }

    /**
     * 查询dex文件地址以及hash值
     * @param call  回调
     */
    public void queryDex(CallQueryDex call) {
        Request r = newReq( mBuild.apiQueryDex() );
        //当前App的版本
        r.addParam(mBuild.getParamVersion(), AppUtil.getVerName( mContext ));
        r.setCallbackString(s -> {
            List<String> url = null, hash = null;
            String checkID = null, ver = null;
            try {
                JSONObject json = JSONObject.parseObject( reqBase(s) );
                url = json.getJSONArray(DEX_FILE_URL).toJavaList(String.class);
                hash = json.getJSONArray(DEX_HASH).toJavaList(String.class);
                ver = json.getString(VER);
                checkID = json.getString(DEX_CHECK_ID);
            } catch (Exception e) {
                e.printStackTrace();
            }
            if( call != null ) call.call(url, hash, checkID, ver);
            if( url == null ) LogUtil.e("Dex file url list for failure.");
            if( hash == null ) LogUtil.e("Dex file hash list for failure.");
        });
        reqPost( r );
    }

    /**
     * 修复检查
     * @param call  回调
     */
    public void checkRepair(CallCheckID call) {
        Request r = newReq( mBuild.apiCheckRepair() );
        //当前App的版本
        r.addParam(mBuild.getParamVersion(), AppUtil.getVerName( mContext ));
        r.setCallbackString(s -> {
            String dexCheckID = null;
            try {
                JSONObject json = JSONObject.parseObject( reqBase(s) );
                dexCheckID = json.getString(DEX_CHECK_ID);
            } catch (Exception e) {
                e.printStackTrace();
            }
            if( call != null ) call.call( dexCheckID );
            if( dexCheckID == null ) LogUtil.e("Dex check id for failure.");
        });
        reqPost( r );
    }

    /**
     * 构建请求。允许自定义设置服务器的请求链接、接口、参数名称
     * @param build     构建的请求
     * @return          this
     */
    public <T extends BaseReqBuild> RequestManage setReqBuild(T build) {
        mBuild = build;
        return this;
    }

    public String toReqBuild() { return mBuild.toString(); }

    public RequestManage setServerUrl(String url) {
        mBuild.setServerUrl( url );
        return this;
    }

    /**
     * 请求时可能需要的Token
     * @param token     唯一标识符
     * @return          this
     */
    public RequestManage setToken(String token) {
        this.token = token;
        return this;
    }

    private <T extends Request> void reqPost(T r) {
        if( token != null ) r.addParam(mBuild.getParamToken(), token);
        mHttpManage.sendPost( r );
        LogUtil.d("Req:" + r.toString());
    }

    private Request newReq(String api) {
        return new Request() {
            @Override
            public String url() { return mBuild.getServerUrl(); }
            @Override
            public String api() { return api; }
        };
    }

    @Nullable
    private String reqBase(String s) {
        int status = -1;
        String msg = null;
        try {
            JSONObject json = JSONObject.parseObject( s );
            status = json.getIntValue(STATUS);
            if( status == mBuild.getDefStatusOfSuccess() ) return json.getString(DATA);
            msg = json.getString(MSG);
        } catch (Exception e) {
            e.printStackTrace();
        }
        LogUtil.e(String.format(
                "The returned data resolution fail:{msg:{%s},status:{%s}}", msg, status)
        );
        return null;
    }

    private String doSavePath(@NonNull String path) {
        return path.endsWith(File.separator) ? path : path + File.separator;
    }

    private class DownloadAdapter implements DownloadListener {
        @Override
        public void taskStart(@NonNull DownloadTask task) { }
        @Override
        public void connectTrialStart(@NonNull DownloadTask task,
                                      @NonNull Map<String, List<String>> requestHeaderFields) { }
        @Override
        public void connectTrialEnd(@NonNull DownloadTask task, int responseCode,
                                    @NonNull Map<String, List<String>> responseHeaderFields) { }
        @Override
        public void downloadFromBeginning(@NonNull DownloadTask task, @NonNull BreakpointInfo info,
                                          @NonNull ResumeFailedCause cause) { }
        @Override
        public void downloadFromBreakpoint(@NonNull DownloadTask task,
                                           @NonNull BreakpointInfo info) { }
        @Override
        public void connectStart(@NonNull DownloadTask task, int blockIndex,
                                 @NonNull Map<String, List<String>> requestHeaderFields) { }
        @Override
        public void connectEnd(@NonNull DownloadTask task, int blockIndex, int responseCode,
                               @NonNull Map<String, List<String>> responseHeaderFields) { }
        @Override
        public void fetchStart(@NonNull DownloadTask task, int blockIndex, long contentLength) { }
        @Override
        public void fetchProgress(@NonNull DownloadTask task,
                                  int blockIndex, long increaseBytes) { }
        @Override
        public void fetchEnd(@NonNull DownloadTask task, int blockIndex, long contentLength) { }
        @Override
        public void taskEnd(@NonNull DownloadTask task, @NonNull EndCause cause,
                            @Nullable Exception realCause) {

        }
    }
}